/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sim;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/**
 *
 * @author Quest
 */

public class Sim extends JPanel implements Runnable {

    private Ellipse2D.Double circle;
    //private Rectangle2D.Double rect;
    private List<Rectangle> rects = new ArrayList<Rectangle>();
    private List<Face> faces = new ArrayList<Face>();
    double radius = 20;
    private final int similar_width = 50;
    private final int translation_x = 100;
    private final int translation_y = 100;
    private int status = 0;
    private int obst = 0;
    private int int_obst_x = 0;
    private int int_obst_y = 0;
    private int x = 0;
    private int y = 0;
    Graphics2D g2;
    private int trans_x_grid = 1;
    private int trans_y_grid = 1;
    
    public Sim() {
        setBackground(Color.WHITE);
        setFocusable(true);
    }

    @Override
    public void run() {

        String clientSentence;
        String capitalizedSentence;
        try {
            ServerSocket svSocket = new ServerSocket(14188);
            while (true) {
                Socket connectionSocket = svSocket.accept();
                BufferedReader inFromClient =
                        new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
                DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
                clientSentence = inFromClient.readLine();
                System.out.println("Received: " + clientSentence);
                //System.out.println(clientSentence.indexOf('('));
                //String cmd = clientSentence.substring(0, 10);
                if (processMes(clientSentence) == 0) {
                    System.out.println("The command's format is invalid!");
                    outToClient.writeBytes("The command's format is invalid! Please send the command again!");
                }
                repaint();
                capitalizedSentence = clientSentence.toUpperCase() + '\n';
                outToClient.writeBytes(capitalizedSentence);
            }
        } catch (Exception exc) {
            System.out.print(exc.getMessage());
        }

    }

    private int processMes(String message) {

        /*
         * Format of command:
         *   CREATEGRID(num_x,num_y;root_x,root_y)
         *   CREATENODE(x,y,color)
         *   MOVEFROMTO(x1,y1,color1;x2,y2)
         *   DELETENODE(x,y,color)
         *   CHANGECLOR(x,y,old_color, new_color)
         *   CREATEOBST(x,y)
         * Format of color:
         *   0 - Black
         *   1 - White
         *   2 - Red
         *   3 - Blue
         */

        int begin = message.indexOf('(');
        int first_sign = message.indexOf(',', begin);
        int end = message.indexOf(')');
        //String cmd = message.substring(0, begin);
        if (begin == 10) {
            String cmd = message.substring(0, begin);
            cmd = cmd.toUpperCase();
            System.out.print(cmd + "\n");
            try {
                if (cmd.equalsIgnoreCase("CREATEGRID")) {
                    int second_sign = message.indexOf(';', first_sign + 1);
                    int third_sign = message.indexOf(',', second_sign + 1);

                    String charX = message.substring(begin + 1, first_sign);
                    String charY = message.substring(first_sign + 1, second_sign);
                    String str_root_x = message.substring(second_sign + 1, third_sign);
                    String str_root_y = message.substring(third_sign + 1, end);
                    int int_x = Integer.parseInt(charX);
                    int int_y = Integer.parseInt(charY);
                    int int_root_x = Integer.parseInt(str_root_x);
                    int int_root_y = Integer.parseInt(str_root_y);
                    
                    
                    System.out.println("x = " + charX + ", y = " + charY + ", root_x = " + str_root_x + ", root_y = " + str_root_y);

                    trans_x_grid = int_root_x;
                    trans_y_grid = int_root_y;
                    /*
                    String charX = message.substring(begin + 1, first_sign);
                    String charY = message.substring(first_sign + 1, end);
                    int int_x = Integer.parseInt(charX);
                    int int_y = Integer.parseInt(charY);
                    System.out.println("x = " + charX + ", y = " + charY);
                     */
                    createGrid(int_x -1 , int_y - 1);
                    return 1;

                } else if (cmd.equalsIgnoreCase("CREATENODE")) {
                    int second_sign = message.indexOf(',', first_sign + 1);
                    String charX = message.substring(begin + 1, first_sign);
                    String charY = message.substring(first_sign + 1, second_sign);
                    String str_color = message.substring(second_sign + 1, end);
                    double double_x = Double.parseDouble(charX) - trans_x_grid + 1;
                    double double_y = Double.parseDouble(charY) - trans_y_grid + 1;
                    int int_color = Integer.parseInt(str_color);
                    System.out.println("x = " + charX + ", y = " + charY + ", color = " + str_color);
                    createNode(double_x - 1, double_y - 1, int_color);
                    return 1;

                } else if (cmd.equalsIgnoreCase("MOVEFROMTO")) {

                    int second_sign = message.indexOf(',', first_sign + 1);
                    int third_sign = message.indexOf(';', second_sign + 1);
                    int fourth_sign = message.indexOf(',', third_sign + 1);

                    String charX1 = message.substring(begin + 1, first_sign);
                    String charY1 = message.substring(first_sign + 1, second_sign);
                    String str_color = message.substring(second_sign + 1, third_sign);
                    String charX2 = message.substring(third_sign + 1, fourth_sign);
                    String charY2 = message.substring(fourth_sign + 1, end);
                    int int_x1 = Integer.parseInt(charX1) -  trans_x_grid + 1;
                    int int_y1 = Integer.parseInt(charY1) -  trans_y_grid + 1;
                    int int_x2 = Integer.parseInt(charX2) -  trans_x_grid + 1;
                    int int_y2 = Integer.parseInt(charY2) -  trans_y_grid + 1;
                    int int_color = Integer.parseInt(str_color);
                    System.out.println("x1 = " + charX1 + ", y1 = " + charY1 + ", color = " + str_color + ", x2 = " + charX2 + ", y2 = " + charY2);
                    moveFromTo(int_x1 - 1, int_y1 - 1, int_color, int_x2 - 1, int_y2 - 1);
                    return 1;

                } else if (cmd.equalsIgnoreCase("DELETENODE")) {

                    int second_sign = message.indexOf(',', first_sign + 1);
                    String charX = message.substring(begin + 1, first_sign);
                    String charY = message.substring(first_sign + 1, second_sign);
                    String str_color = message.substring(second_sign + 1, end);
                    int int_x = Integer.parseInt(charX) -  trans_x_grid + 1;
                    int int_y = Integer.parseInt(charY) -  trans_y_grid + 1;
                    int int_color = Integer.parseInt(str_color);
                    System.out.println("x = " + charX + ", y = " + charY + ", color = " + str_color);
                    deleteNode(int_x - 1, int_y - 1, int_color);
                    return 1;

                } else if (cmd.equalsIgnoreCase("CHANGECLOR")) {

                    int second_sign = message.indexOf(',', first_sign + 1);
                    int third_sign = message.indexOf(',', second_sign + 1);
                    String charX = message.substring(begin + 1, first_sign);
                    String charY = message.substring(first_sign + 1, second_sign);
                    String str_color1 = message.substring(second_sign + 1, third_sign);
                    String str_color2 = message.substring(third_sign + 1, end);
                    int int_x = Integer.parseInt(charX) -  trans_x_grid + 1;
                    int int_y = Integer.parseInt(charY) -  trans_y_grid + 1;
                    int int_color1 = Integer.parseInt(str_color1);
                    int int_color2 = Integer.parseInt(str_color2);
                    System.out.println("x = " + charX + ", y = " + charY + " , old color = " + str_color1 + ", new color = " + str_color2);
                    changeColor(int_x - 1, int_y - 1, int_color1, int_color2);
                    return 1;

                } else if (cmd.equalsIgnoreCase("CREATEOBST")) {

                    String charX = message.substring(begin + 1, first_sign);
                    String charY = message.substring(first_sign + 1, end);
                    int int_x = Integer.parseInt(charX) - trans_x_grid + 1;
                    int int_y = Integer.parseInt(charY) - trans_y_grid + 1;
                    System.out.println("x = " + charX + ", y = " + charY);
                    int_obst_x = int_x - 1;
                    int_obst_y = int_y - 1;
                    obst = 1;
                    //createObst(int_x - 1, int_y - 1);
                    return 1;

                } else if (cmd.equalsIgnoreCase("VIEWPOINTS")) {
                    System.out.println(faces.size());
                    for (int i=0; i < faces.size(); i++) {
                        System.out.println("x = " + faces.get(i).x + " - y = " + faces.get(i).y + " - color = " + faces.get(i).getColor());
                    }
                    return 1;
                } else {
                    return 0;
                }
            } catch (Exception exc) {
                System.out.println(exc.getMessage());
                return 0;
            }
        } else {
            return 0;
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        //Graphics2D g2 = (Graphics2D) g;
        g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        for (Face face : faces) {
            face.paint(g2);
        }
        /*
        if (rect != null) {
            if (circle == null) {
                g2.setColor(Color.RED);
            } else {
                g2.draw(circle);
            }
            g2.setStroke(new BasicStroke(1.0f,
                    BasicStroke.CAP_BUTT,
                    BasicStroke.JOIN_BEVEL,
                    1.0f,
                    new float[]{0.8f, 6.0f},
                    0.0f));
            g2.draw(rect);
        }
         */

        if (status == 1) {
            int x_grid = translation_x;
            int y_grid = translation_y;
            for (int i = 0; i < x; i++) {
                for (int j = 0; j < y; j++) {
                    g.drawRect(x_grid, y_grid, similar_width, similar_width);
                    x_grid += similar_width;
                }
                x_grid = translation_x;
                y_grid += similar_width;
            }
        }
        
        if (obst != 0) {
            createObst(int_obst_x, int_obst_y);
        }
        paintObst();
    }

    public void makeUI() {

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        //frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        frame.add(this);
        frame.setTitle("SIM - RB");
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {

                //new sim().makeUI();
                Sim s = new Sim();
                s.makeUI();
                new Thread(s).start();

            }
        });
    }

    private void createGrid(int num_x, int num_y) {

        x = num_x;
        y = num_y;
        status = 1;
        repaint();

    }

    private void paintObst(){
        for (Rectangle rect : rects) {
            g2.fillRect(rect.int_x, rect.int_y, rect.int_width, rect.int_height);
        }
    }

    private synchronized void createObst(int int_x, int int_y) {

        System.out.println("tran x = " + trans_x_grid + "tran y = " + trans_y_grid);
        System.out.println("x = " + int_x + " y = " + int_y);
        int width = similar_width;
        int height = similar_width;
        if ((int_x == x) && (int_y == y)) {
            width = similar_width / 2;
            height = similar_width / 2;
        } else if (int_x == x){
            if (int_y == trans_y_grid) {
                height = similar_width / 2;
            }
            width = similar_width / 2;
        } else if (int_y == y) {
            if (int_x == trans_x_grid) {
                width = similar_width / 2;
            }
            height = similar_width / 2;
        }
        int_x = translation_x + int_x * similar_width - similar_width / 2;
        int_y = translation_y + int_y * similar_width - similar_width / 2;
        //Rectangle2D.Double rectangle = new Rectangle2D.Double(double_x, double_y, radius, radius);
        
        Rectangle rectangle = new Rectangle(int_x, int_y, width, height);
        rects.add(rectangle);
        obst = 0;

    }

    private void createNode(double x, double y, int int_color) {

         

        x = translation_x + x * similar_width - radius / 2;
        y = translation_y + y * similar_width - radius / 2;
        circle = new Ellipse2D.Double(x, y, radius, radius);

/*
         Ellipse2D.Double nose = new Ellipse2D.Double(x, y, radius, radius);
         Point2D.Double focus = new Point2D.Double(x, y);
         float[] floats = {0.01f, 0.2f, 1.0f};
         Color[] colors = {Color.WHITE, Color.RED, Color.RED.darker()};
         RadialGradientPaint paint = getPaint(nose, focus, floats, colors);
         g2.setPaint(paint);
         g2.fill(nose);
         g2.setColor(Color.BLACK);
         g2.draw(nose);
*/
        //faces.add(new Face(circle));  
        faces.add(new Face(circle, int_color));
        //repaint();
        circle = null;
        //rect = null;
        repaint();

    }

    private void deleteNode(int x, int y, int int_color) {

        Face face = getFaceAt(setPoint(x, y), int_color);
        if (face != null) {
            System.out.println("Found!");
            faces.remove(face);
        } else {
            //Do something
        }
        repaint();
        System.out.println("Deleted " + x + " - " + y + " - " + int_color);

    }

    private void moveFromTo(int x1, int y1, int int_color, int x2, int y2) {

        deleteNode(x1, y1, int_color);
        System.out.println("Deleted " + x1 + " - " + y1 + " - " + int_color);

//        double double_x = translation_x + x2 * similar_width - radius / 2;
//        double double_y = translation_y + y2 * similar_width - radius / 2;
//        circle = new Ellipse2D.Double(double_x, double_y, radius, radius);
//        faces.add(new Face(circle));
//        circle = null;
        createNode(x2, y2, int_color);
        repaint();

    }

    private void changeColor(int int_x, int int_y, int old_color, int new_color) {

        Face face = getFaceAt(setPoint(int_x, int_y), old_color);
        //if ((face != null) && (face.getColor() == old_color)) {
        if (face != null) {
            face.setColor(new_color);
        } else {
            //Do something
        }
        repaint();

    }
/*
    private RadialGradientPaint getPaint(Ellipse2D.Double circle,
            Point2D.Double focus, float[] floats, Color[] colors) {

        Point2D.Double center = new Point2D.Double(circle.getCenterX(),
                circle.getCenterY());
        return new RadialGradientPaint(center, (float) circle.width, focus,
                floats, colors, CycleMethod.NO_CYCLE);

    }
*/
    private Point setPoint(int x, int y) {

        x = translation_x + x * similar_width;
        y = translation_y + y * similar_width;
        double double_x = x;
        double double_y = y;
        Point p = new Point();
        p.setLocation(double_x, double_y);
        return p;

    }

    private Face getFaceAt(Point p, int int_color) {

        Face faceAtP = null;
        for (int i = faces.size() - 1; i >= 0; i--) {
            if (faces.get(i).contains(p) && (faces.get(i).getColor() == int_color)) {
                faceAtP = faces.get(i);
                faces.remove(faceAtP);
                faces.add(faceAtP);
                break;
            }
        }
        return faceAtP;

    }
    
}